/************************************************************
 * Copyright (C), 2022-2030, ripnano. Co., Ltd.
 * FileName:        can_manage.h
 * Author:          Dan Yin
 * Date:            2023-05-12
 * Description:     the class of CAN bus data manager
 * Version:         1.0.0.0
 **********************************************************/

#ifndef CAN_MANAGE_H
#define CAN_MANAGE_H

// add necessary includes here
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QMutexLocker>
#include <QSemaphore>
#include <QCoreApplication>
#include <QTimer>
#include <QQueue>

#include "cycle_buffer.h"
#include "share_function.h"
#include "defines/def_frame_protocol.h"

#ifdef QT_PROJECT_T4
#define DEF_IAP_MODULE_SIZE     4
#define DEF_PCR_MODULE_SIZE     0
#elif QT_PROJECT_T5
#define DEF_IAP_MODULE_SIZE     4
#define DEF_PCR_MODULE_SIZE     0
#elif QT_PROJECT_T1C
#define DEF_IAP_MODULE_SIZE     3
#define DEF_PCR_MODULE_SIZE     0
#else
#define DEF_IAP_MODULE_SIZE     4
#define DEF_PCR_MODULE_SIZE     8
#endif

class CanManage : public QThread
{
    Q_OBJECT

public:
    // Get an instance of "CanManage" class, if exist, return it
    static CanManage* getInstance(QObject *pParent = nullptr);

    // The default destructor
    virtual ~CanManage();

    void startThread() {
        m_bExitThread = false;
        this->start();
    }

    void stopThread() {
        m_semaphore.release(m_semaphore.available());
        m_bExitThread = true;
    }

signals:
    // Send an frame data to CAN bus
    int signalSendFrameData(unsigned int nFrameId, const QByteArray &baFrameData, bool bQueued);

    // The signal that received data from CAN
    void signalDataReceived(unsigned int unCanId, QByteArray baPacket);

private slots:
    // Received data from CAN
    void slotFramesReceived(unsigned int unCanId, QByteArray baPayload);

    // reply an ACK command to CAN
    int slotReplyACK(QByteArray baPacket, bool bQueued);

private:
    // The default constructor
    explicit CanManage(QObject *parent = nullptr);

    // After constructing object, initialize the object
    void _initialze();

    // Rewrite the run() function of QThread
    void run();

    // Concatenated data packet from CAN
    void _concatenatedDataFromIAP(int nCanIdx);

    // Concatenated PCR data packet from CAN
    void _concatenatedDataFromPCR(int nCanIdx);

private:
    // the buffer for serialport
    CycleBuffer<char>   m_bufRecvIAP[DEF_IAP_MODULE_SIZE];
    CycleBuffer<char>   m_bufRecvPCR[DEF_PCR_MODULE_SIZE];

    unsigned char       m_szDataCRC[1024];
    volatile bool       m_bExitThread = true;
    mutable QMutex      m_mtxRecv;
    mutable QMutex      m_mtxProc;
    QSemaphore          m_semaphore;
    QTimer              m_tmrWatchdog;
};

#endif // CAN_MANAGE_H
